package com.supreme.threadserver.controller;

import com.supreme.commonboot.utils.AjaxResp;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.Objects;
import java.util.concurrent.*;

@RestController
@RequestMapping(value = "thread-life")
public class ThreadLifeController {

    private ThreadPoolExecutor threadPoolExecutor;

    @PostConstruct
    private void controllerInit() {
        int poolSize = 4;
        long keepAliveTime = TimeUnit.SECONDS.toSeconds(10);
        threadPoolExecutor = new ThreadPoolExecutor(
                poolSize,
                poolSize * 2,
                keepAliveTime,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(poolSize),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    @GetMapping(value = "simpleThread")
    public AjaxResp simpleThread() {
        for (int i = 1; i <= 4; i++) {
            int finalI = i;
            new Thread(() -> {
                Thread thread = Thread.currentThread();
                System.out.printf("Thread ID = %d Name = %s Start\n", thread.getId(), thread.getName());
                try {
                    TimeUnit.SECONDS.sleep(finalI * 20);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.printf("Thread ID = %d Name = %s Finish\n", thread.getId(), thread.getName());
            }, "SimpleThread-" + i).start();
        }

        return AjaxResp.instance();
    }

    @GetMapping(value = "countDownLatch")
    public AjaxResp countDownLatch() {
        CountDownLatch countDownLatch = new CountDownLatch(4);

        for (int i = 1; i <= 4; i++) {
            int finalI = i;
            new Thread(() -> {
                Thread thread = Thread.currentThread();
                System.out.printf("Thread ID = %d Name = %s Start\n", thread.getId(), thread.getName());
                try {
                    TimeUnit.SECONDS.sleep(finalI * 20);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.printf("Thread ID = %d Name = %s Finish\n", thread.getId(), thread.getName());
            }, "CountDownLatchThread-" + i).start();
        }

        try {
            countDownLatch.await();
            System.out.println("CountDownLatchThread AllDone");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return AjaxResp.instance();
    }

    @GetMapping(value = "cyclicBarrier")
    public AjaxResp cyclicBarrier() {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(4, () -> {
            Thread thread = Thread.currentThread();
            System.out.printf("cyclicBarrier ID = %d Name = %s\n", thread.getId(), thread.getName());
        });

        for (int i = 1; i <= 4; i++) {
            int finalI = i;
            new Thread(() -> {
                Thread thread = Thread.currentThread();
                System.out.printf("Thread ID = %d Name = %s Start\n", thread.getId(), thread.getName());

                try {
                    TimeUnit.SECONDS.sleep(finalI * 20);
                    System.out.printf("Thread ID = %d Name = %s Await\n", thread.getId(), thread.getName());
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    throw new RuntimeException(e);
                }
                System.out.printf("Thread ID = %d Name = %s Finish\n", thread.getId(), thread.getName());
            }, "CyclicBarrierThread-" + i).start();
        }

        return AjaxResp.instance();
    }

    @GetMapping(value = "semaphore")
    public AjaxResp semaphore() {
        Semaphore semaphore = new Semaphore(4);

        for (int i = 1; i <= 4; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    semaphore.acquire(1);

                    Thread thread = Thread.currentThread();
                    System.out.printf("Thread ID = %d Name = %s Start\n", thread.getId(), thread.getName());
                    TimeUnit.SECONDS.sleep(finalI * 20);
                    System.out.printf("Thread ID = %d Name = %s Release\n", thread.getId(), thread.getName());
                    semaphore.release(1);
                    System.out.printf("Thread ID = %d Name = %s Finish\n", thread.getId(), thread.getName());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }, "SemaphoreThread-" + i).start();
        }

        return AjaxResp.instance();
    }

    @GetMapping(value = "threadPool")
    public AjaxResp threadPool() {
        for (int i = 1; i <= 4; i++) {
            int finalI = i;
            Thread workThread = new Thread(() -> {
                try {
                    Thread thread = Thread.currentThread();
                    System.out.printf("Thread ID = %d Name = %s Start\n", thread.getId(), thread.getName());
                    TimeUnit.SECONDS.sleep(finalI * 20);
                    System.out.printf("Thread ID = %d Name = %s Finish\n", thread.getId(), thread.getName());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }, "ThreadPoolThread-" + i);
            threadPoolExecutor.execute(workThread);
        }

        return AjaxResp.instance();
    }

    @GetMapping(value = "destroyThreadPool")
    public AjaxResp destroyThreadPool() {
        if (Objects.nonNull(threadPoolExecutor)) {
            if (threadPoolExecutor.isShutdown()) {
                threadPoolExecutor.shutdown();
            }
        }
        return AjaxResp.instance();
    }
}
